
#pragma once 

#include "Matrix4.h" 
#include "Vector3.h" 

class Quaternion
{
public :
	float X,Y,Z;
	float W;
	Quaternion();
	Quaternion(const float _W, const float _x, const float _y, const float _z);
	Quaternion(const float _W, const Vector3 &vec);
	/// from 3 Euler angles
	Quaternion(const float theta_z, const float theta_y, const float theta_x);
	/// from 3 Euler angles 
	Quaternion(const Vector3 &angles);	
	
	//////////////////////////////////////////////////////////////////////////
	/// OPERATOR
	//////////////////////////////////////////////////////////////////////////
	Quaternion &operator =(const Quaternion &q);

	Quaternion operator + (const Quaternion &q) const;		
	Quaternion operator -(const Quaternion &q) const;
	Quaternion operator *(const Quaternion &q) const;	
	Quaternion operator /(const Quaternion &q) const;

	const Quaternion operator *(const float scale) const;
	const Quaternion operator /(float scale) const;
	
	Quaternion operator -() const;
	
	Quaternion &operator +=(const Quaternion &q);
	Quaternion &operator -=(const Quaternion &q);
	Quaternion &operator *=(const Quaternion &q);		
	
	Quaternion &operator *= (const float scale);		
	const Quaternion &operator /= (const float scale);
	

	//////////////////////////////////////////////////////////////////////////
	/// QUATERNION FUNCTIONS
	//////////////////////////////////////////////////////////////////////////
	/// gets the length of this Quaternion
	float length() const;

	/// gets the squared length of this Quaternion
	float length_Squared() const;

	/// normalizes this Quaternion
	void normalize();
	
	/// returns the normalized version of this Quaternion
	Quaternion normalized() const;

	/// computes the conjugate of this Quaternion
	void conjugate();
	
	/// inverts this Quaternion
	void invert();
	
	/// returns the logarithm of a Quaternion = v*a where q = [cos(a),v*sin(a)]
	Quaternion logarit() const;
	/// returns e^Quaternion = exp(v*a) = [cos(a),vsin(a)]
	Quaternion exp() const;

	/// casting to a 4x4 isomorphic matrix for right multiplication with vector
	Matrix4 toMatrix4() const;
	
	/// returns the axis and angle of this unit Quaternion
	void to_axis_angle(Vector3 &axis, float &angle) const;

	/// rotates v by this Quaternion (Quaternion must be unit)
	Vector3 rotate(const Vector3 &v);

	/// returns the euler angles from a rotation Quaternion
	Vector3 euler_angles() const;


	//////////////////////////////////////////////////////////////////////////
	/// STATIC FUNCTIONS
	//////////////////////////////////////////////////////////////////////////
	
	/// computes the dot product of 2 Quaternions
	static inline float dot(const Quaternion &q1, const Quaternion &q2) 
	{
		return q1.X*q2.X +q1.Y*q2.Y +q1.Z*q2.Z + q1.W*q2.W;
	}

	/// linear Quaternion interpolation
	static Quaternion lerp(const Quaternion &q1, const Quaternion &q2, float t) ;

	/// spherical linear interpolation
	static Quaternion slerp(const Quaternion &q1, const Quaternion &q2, float t);

	/// This version of slerp, used by squad, does not check for theta > 90.
	static Quaternion slerpNoInvert(const Quaternion &q1, const Quaternion &q2, float t);

	/// spherical cubic interpolation
	static Quaternion squad(const Quaternion &q1,const Quaternion &q2,const Quaternion &a,const Quaternion &b,float t);

	/// Shoemake-Bezier interpolation using De Castlejau algorithm
	static Quaternion bezier(const Quaternion &q1,const Quaternion &q2,const Quaternion &a,const Quaternion &b,float t);

	/// Given 3 Quaternions, qn-1,qn and qn+1, calculate a control point to be used in spline interpolation
	static Quaternion spline(const Quaternion &qnm1,const Quaternion &qn,const Quaternion &qnp1);

	/// converts from a normalized axis - angle pair rotation to a Quaternion
	static Quaternion from_axis_angle(const float angle,const Vector3 &axis);
	static Quaternion from_axis_angle(const float angle,const float XAxis,const float YAxis,const float ZAxis);
	
};